#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>

#define MAXTITL 40
#define MAXAUTH 40
#define MAXBKS 10

#define FNAME "book.bat"

//curd constant
typedef enum {add = 1, edit, delete, quit} Handle;

//book structure
struct book {
    char title[MAXTITL];
    char author[MAXAUTH];
    float value;
    bool del;
};

//book memory size
static size_t book_men_size = sizeof(struct book);

//to read content of FNAME
static struct book library[MAXBKS];

void init(FILE **, struct book **, int *);

void addBook(FILE *, struct book **, int *);
void editBook(FILE *, struct book **, int *);
void rmBook(FILE *, struct book **, int *);

int menu(void);
void print_content(struct book **, int);

char * s_gets(char * , int);
void eatline(void);

int main(void)
{
    struct book * quick[MAXBKS];

    int choice;

    int count = 0;
    int index = 0;

    FILE * pbooks;

    init(&pbooks, quick, &count);

    print_content(quick, count);

    while ((choice = menu()) != quit) {
        switch (choice) {
            case add:
                addBook(pbooks, quick, &count);
                break;

            case edit:
                editBook(pbooks, quick, &count);
                break;

            case delete:
                rmBook(pbooks, quick, &count);
                break;

            case quit:
            default:
                break;
        }

        if (choice == quit)
            break;
    }

    if (count > 0) {
        puts("Here is the list of your books.");
        print_content(quick, count);
    } else
        puts("No books? Too bad.\n");

    puts("Bye.\n");

    fclose(pbooks);

    return 0;
}

void print_content(struct book ** quick, int count)
{
    int i;
    puts("-----------------------------------------------------------");
    for (i=0; i<count; ++i) {
        printf("%d) %s by %s : $%.1f.\n", i+1, quick[i]->title, quick[i]->author, quick[i]->value);
    }
    puts("-----------------------------------------------------------");

}

int menu(void)
{
    int choice = quit;

    puts("1) add new book   2) edit book");
    puts("3) remove book    4) quit");

    while (scanf("%d", &choice) == 1) {
        if (choice < add || choice > quit) {
            puts("Enter correct value.");
            continue;
        }
        eatline();
    }

    return choice;
}

void init(FILE ** fp, struct book ** quick, int * count)
{
    int i=0;

    //if file isn't exists
    if (access(FNAME, F_OK) != 0) {
        *fp = fopen(FNAME, "wb");
        fclose(*fp);
    }

    //open file use "r+b"
    if ((*fp = fopen(FNAME, "r+b")) == NULL) {
        fprintf(stdout, "file [%s] open failed!\n", FNAME);
        exit(EXIT_FAILURE);
    }

    while (i < MAXBKS && fread(&library[i], book_men_size, 1, *fp) == 1) {
        *(quick + i) = library + i;
        library[i++].del = 0;
    }

    *count =i;

    for (; i<MAXBKS; ++i)
        library[i].del = 1;

}

void addBook(FILE * fp, struct book ** quick, int * count)
{
    int i=0;

    if (*count == MAXBKS) {
        printf("the file %s is full.\n", FNAME);
        return;
    }

    for (i=0; i<MAXBKS; ++i) {
        if (library[i].del == 1)
            break;
    }

    if (i == MAXBKS) {
        fprintf(stderr, "Exception occur, no found store position!");
        exit(EXIT_FAILURE);

    } else
        quick[*count] = library + i;

    puts("Please add new book titles.");
    puts("Press [enter] at the start of a line to stop.");

    if (*count < MAXBKS && s_gets(quick[*count]->title, MAXTITL) && quick[*count]->title[0] != 0) {
        puts("Enter the author.");
        s_gets(quick[*count]->author, MAXAUTH);

        puts("Enter the value.");
        scanf("%f", &quick[*count]->value);
        eatline();

        if (-1 == fseek(fp, *count * book_men_size, SEEK_SET)) {
            fprintf(stderr, "move pointer failed!");
            exit(EXIT_FAILURE);
        }

        puts("Writing file...");
        if (fwrite(quick[*count], book_men_size, 1, fp) != 1) {
                fprintf(stderr, "update failed!");
                exit(EXIT_FAILURE);

            } else
                puts("update success.");

            quick[(*count)++]->del = 0;

   //     if (*count != MAXBKS)
   //         puts("Please add new book titles.");

    }

}

void editBook(FILE * fp, struct book ** quick, int * count)
{
    int choice;
    struct book * pt;
    char tmp[MAXTITL];
    float tmpv;

    printf("Enter book number [%d~%d] ", 1, *count);
    printf("(enter 0 to quit).\n");

    while (scanf("%d", &choice) == 1) {
        eatline();

        if (choice <1 || choice > *count)
        {
            if (choice == 0)
                break;

            printf("Enter book number [%d~%d]: ", 1, *count);
            continue;
        }

        fseek(fp, (choice - 1) * sizeof(struct book), SEEK_SET);

        pt = quick[choice - 1];

        printf("Enter new title(%s):\n", pt->title);
        printf("Enter empty line indication does not nodify.\n");
        s_gets(tmp, MAXTITL);
        if (tmp[0] != 0)
            strcpy(pt->title, tmp);

        printf("Enter new author(%s):\n", pt->author);
        s_gets(tmp, MAXTITL);
        if (tmp[0] != 0)
            strcpy(pt->author, tmp);

        printf("Enter new value(%.1f)\n", pt->value);
        scanf("%f", &tmpv);
        if (tmpv > 0.001)   //fabs
            pt->value = tmpv;


        if (fwrite(pt, book_men_size, 1, fp) != 1) {
            fprintf(stderr, "update failed!");
            exit(EXIT_FAILURE);

        } else
            puts("update success.");

        printf("Enter book number [%d~%d]:\n", 1, *count);

    }

}

void rmBook(FILE * fp, struct book ** quick, int * count)
{
    int choice;
    int i;

    puts("Please enter the number of book that you want delete.");
    printf("Enter number of book [%d~%d] (0 to quit):\n", 1, *count);

    while (scanf("%d", &choice) == 1) {
        if (choice < 1 || choice > *count) {
            if (0 == choice)
                break;

            printf("Please enter correct number [%d~%d].", 1, *count);
            continue;
        }

        library[choice-1].del = 1;

        for (i = choice-1; i<*count-1; ++i)
            quick[i] = quick[i+1];

        if (fseek(fp, (choice - 1) * book_men_size, SEEK_SET) == -1) {
            fprintf(stderr, "fseek位置变更失败.");
            exit(EXIT_FAILURE);
        }

        if (fwrite(quick[choice - 1], book_men_size, *count - choice, fp) == 0) {
            fprintf(stderr, "写入文件失败");
            exit(EXIT_FAILURE);
        }


        --(*count);

        puts("Please enter the number.");
    }


}

char * s_gets(char * pt, int n)
{
    char * ret_val;
    char * find;

    if ((ret_val = fgets(pt, n, stdin)) != NULL) {
        find = strchr(pt, '\n');
        if (find)
            *find = 0;
        else
            while (getchar() != '\n')
                ;
    }

    return ret_val;
}

void eatline(void) {
    while (getchar() != '\n')
        ;
}
